import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;


import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.Timer;


public class Panel extends JPanel implements ActionListener{
		
		//resources
		Image map;
		BufferedImage waiting;
		BufferedImage marker;
		BufferedImage motionMarker;
		BufferedImage markerSquare;
		
		UAV uav;
		PanelClickHandler clickHandler;
		Main main_delegate;
		Timer time;
		List<Point> pointList = new ArrayList<Point>();//stores all points to be displayed on screen
		List<Point> motionList = new ArrayList<Point>();
		
		
		float scaleLonPPX = .000005f;//419354839;
		float scaleLatPPY = .000004f;//710382514;
		
		float longitude = -81.198454f;
		float latitude = 28.605274f;
		
		int state = -1;//default state
		int sizeX = 563; //panel size not mapsize
		int sizeY = 518; //panel size not mapsize
		
		boolean located;
		boolean closedLoop;
		
		public  Panel(Main $main_delegate) throws IOException{
			
			main_delegate = $main_delegate;
			marker = ImageIO.read(new File("res//marker.png"));
			markerSquare = ImageIO.read(new File("res//marker_square.png"));
			motionMarker = ImageIO.read(new File("res//motionMarker.png"));
			waiting = ImageIO.read(new File("res//waiting.png"));
			uav = new UAV(this);
			this.setBackground(new Color(255,255,255,255));
					
			//TIMER USED TO AUTO UPDATE REPAINT
			time = new Timer(120,this);
			time.start();
			located = false;
			closedLoop = false;
			//testing
			located = true;
			locate();
			this.addMouseListener( clickHandler = new PanelClickHandler(main_delegate,this));
		}
		
		public void gpsReceived(float _latitude,float _longitude){
			
			if(!located){
				
				latitude = _latitude;
				longitude= _longitude;
				located = true;
				
				locate();
				
				this.addMouseListener( clickHandler = new PanelClickHandler(main_delegate,this));
			}
			
			
			uav.setCoordinates(_latitude, _longitude);
			
		}
		
		
		
		
		public void paintComponent(Graphics g) {
			
			Graphics2D g2 = (Graphics2D) g;
			
			if(located){
				//draw map
				g.drawImage(map, 0, 0, null);
		
				
				
				//draw points+lines
				for(Point p: pointList){
					
					
					//drawlines
					if(p.postPoint != null){
						g.drawLine(p.x, p.y, p.postPoint.x, p.postPoint.y);					
					} else {
						//System.out.println("Post point is null");
					}
					
					//draw points
					if(clickHandler.pointBuffer != null){
						if(p.x == clickHandler.pointBuffer.x && p.y == clickHandler.pointBuffer.y){
							g.drawImage(markerSquare, p.x - (marker.getWidth()/2), p.y - (marker.getHeight()/2), null);
						}else{
							g.drawImage(marker, p.x - (marker.getWidth()/2), p.y - (marker.getHeight()/2), null);
							}
					}else{
						g.drawImage(marker, p.x - (marker.getWidth()/2), p.y - (marker.getHeight()/2), null);
					}
				}
				
				
				for(Point p: motionList){
					
					g.drawImage(motionMarker, p.x -(motionMarker.getWidth()/2),p.y - (motionMarker.getHeight()/2),null);
					
				}
				
				//draw UAV blinker
				BufferedImage blink = uav.drawBlinker();
				g.drawImage(blink, uav.x - (blink.getWidth()/2), uav.y - (blink.getHeight()/2), null);
				uav.spritePointer++;
							
				//draw UAV
				g.drawImage(uav.icon, uav.x - (uav.icon.getWidth()/2), uav.y - (uav.icon.getHeight()/2), null);
			} else {
				g.drawImage(waiting,-100,-20,null);
			}
			
			
			
			/*GradientPaint p;
			p = new GradientPaint(0, 50, Color.WHITE, 0, getHeight()*2,new Color(123,53,153));//variation of purple RGB

			Paint oldPaint = g2.getPaint();
			g2.setPaint(p);
			g2.fillRect(0, 0, 800, 600);
			g2.setPaint(oldPaint);
			g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
			g.drawImage(pegasus, 375,500,null);*/
		  }
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			// TODO Auto-generated method stub
			repaint();
			
		}
		
		
		public boolean ltTolerance(int a, int b){
			
			if(Math.abs(a-b) <= StateList.MAX_POINT_TOLERANCE){
				return true;
			}
			
			return false;
		}
		
		
		//TO-DO
		public Point findPoint(Point p,List<Point> list){//find point closest with in MAX_POINT_TOLERANCE
			
			for(Point point: list){
				
				//does point exist
				if(ltTolerance(point.x,p.x) && ltTolerance(point.y,p.y)){
					return point;
				
				}
			}
			
			return new Point(-1,-1,this);//returns a point with x = -1 if not found
		}
		
		
		//TO-DO
		public void newPoint(Point p){//adds new point to pointList
			
			if(pointList.isEmpty()){
				System.out.println("adding point " + p.latitude + " " + p.longitude);
				pointList.add(p);
				main_delegate.setPane("Starting Point:\nLatitude: "+ p.latitude + "\n" + "Longitude:" + p.longitude);
				return;
			}
			
			Point selected = findPoint(p,pointList);
			
			if(selected.x == -1 && pointList.size() < 10){//point doesn't exist
				
				System.out.println("adding point");
				pointList.add(p);
				main_delegate.setPane("Latitude: "+ p.latitude + "\n" + "Longitude:" + p.longitude);
				
				/*if(pointList.size() == 2){
					pointList.get(0).postPoint = pointList.get(1);
					pointList.get(1).prePoint = pointList.get(0);
				}*/
			}else if(selected == pointList.get(0)){//selected point is starting point, close loop
					
					//Point start = pointList.get(0);
					//Point iterator = start;
					
					//while(iterator.postPoint != null)
					//	iterator = iterator.postPoint;
					
					
					//connectPoints(start, iterator);
					main_delegate.setPane(Messages.LOOPCLOSED);
					closedLoop = true;
			}else if(pointList.size() == 10){
				if(p != pointList.get(0) ){
					main_delegate.notify(Messages.LIMIT);
				}
				
			}else {
			
				//warn user: point already exists or too close to existing points
				main_delegate.setPane(Messages.EXISTS);
			}
			
			
		}
		
		//TO-DO
		public void removePoint(Point p) {//removes point from pointList
			if(p.prePoint != null)
				if(p.prePoint.postPoint != null)
					p.prePoint.postPoint = null;
			
			if(p.postPoint != null)
				if(p.postPoint.prePoint != null)
					p.postPoint.prePoint = null;
			
			pointList.remove(p);
			
		}



		public void invalidPoint() {//tells user clicked area isn't close enough to point to recognize
			// TODO Auto-generated method stub
			
		}



		public void connectPoints(Point newPoint, Point oldPoint) {
			
			//main_delegate.notify(Messages.INVALPOINT);
			
			//case : connecting two points which already have other connections
			if(newPoint != null && oldPoint != null){
				if(newPoint.prePoint != null)
					System.out.println("new points pre point is not null");
				else if(oldPoint.postPoint != null) 
					System.out.println("old points post point is not null");
				if(newPoint.prePoint != null || oldPoint.postPoint != null){
					main_delegate.notify(Messages.INVALPOINT);
				}
			}
			newPoint.prePoint = oldPoint;
			if(oldPoint != null){
				System.out.println("old point isnt null");
				//findPoint(oldPoint).postPoint = newPoint;
				oldPoint.postPoint = newPoint;
				
			}
			
			
		}



		public void removeLine(Point pointBuffer, Point findPoint) {
			pointBuffer.postPoint = null;
			findPoint.prePoint = null;
			
		}
		
		
		//CALLED ON A SINGLE BUTTON CLICK
		public void closePath(){//connect first and last node
			//TO-DO
		}
		
		public void clearList(){
			pointList.clear();
			setOrigin();
		}
		
		public void locate() {
			Toolkit tk = getToolkit();
			
			try {
				map = tk.createImage(new URL("http://maps.googleapis.com/maps/api/staticmap?center="+latitude+","+longitude+"&zoom=18&size=563x545&maptype=roadmap&sensor=false"));				
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//"http://maps.googleapis.com/maps/api/staticmap?center="+x+","+y+"&zoom=12&size=563x545&sensor=false"));
			
			setOrigin();
			tk.prepareImage(map, -1, -1, null);
			located = true;
		}
		
		public void setOrigin(){
			newPoint(new Point(sizeX/2,sizeY/2,this));
		}
		
		public void drawMap(double y, double x) throws MalformedURLException{
			Toolkit tk = getToolkit();
			
			map = tk.createImage(new URL("http://maps.googleapis.com/maps/api/staticmap?center="+latitude+","+longitude+"&zoom=18&size=563x545&maptype=roadmap&markers=color:blue%7Clabel:S%7C"+y+","+x+"&markers=color:green%7Clabel:G%7C28.604375,-81.199291&markers=color:red%7Ccolor:red%7Clabel:C%7C28.605274,-81.198454&sensor=false"));//"http://maps.googleapis.com/maps/api/staticmap?center="+x+","+y+"&zoom=12&size=563x545&sensor=false"));
			
		
			tk.prepareImage(map, -1, -1, null);
		}
		
		public Point getLastPoint(){
			Point p = pointList.get(0);
			while(p.postPoint != null)
				p = p.postPoint;
			return p;
		}

		public void markMotion(long timeStamp) {
			
			Point p = new Point(uav.x,uav.y,this);
			
			Point result = findPoint(p, motionList);
			
			if(result.x != p.x){
				motionList.add(p);
			}
		}
}
